This is my Advanced genomics’ project for the AY 2021/2022. Data and code can be retrieved from the following GitHub link.

In protein-protein interaction (PPI from now on) networks (therefore proteins that interact with many other proteins) we distinguish hubs (highly connected nodes/proteins) into party and date categories. This differentiation comes from an analysis (Han et al.) where it was shown that hubs of the PPI network can be assigned to two different categories:
· Hubs that interact with many partners at the same moment (party hubs), which also connect proteins within functional modules such as protein complexes. Party hubs components’ expression is correlated with its interaction partners.
· Hubs that have many targets, but interact with only one or a few of them at any moment (date hubs). In contrast to party hubs, date hubs do not exhibit such a correlation and appear to connect different functional modules.
A popular PPI networks functional enrichment analysis tool is STRING.

The validity of the date hub/party hub distinction was disputed, the concept might not be as general as it seemed when the original publication was presented. In particular, in this paper, the authors showed that the reported importance of date hubs to network connectivity can in fact be attributed to a tiny subset of them.
The date/party distinction was originally motivated by an approximately bimodal distribution of hub co-expression, but this feature is not always robust to methodological changes. Additionally, topological properties of hubs do not in general correlate with co-expression. According to the paper, thinking in terms of a date/party dichotomy for hubs in protein interaction networks is not meaningful, and it might be more useful to conceive of roles for protein-protein interactions rather than for individual proteins.

This project is based on the fact that the party and date hub concept may be interesting to be merged with another topological property of nodes, betweenness centrality, that we can use to introduce the bottleneck concept into the party/date hubs conceptualization. Betweenness (i.e., “bottleneck-ness”) is a much more significant indicator of essentiality than degree (i.e., “hub-ness”). Furthermore, bottlenecks correspond to the dynamic components of the interaction network—they are significantly less well coexpressed with their neighbors than non-bottlenecks, implying that expression dynamics is wired into the network topology.

Therefore, combining hubs and bottlenecks, we can define for instance the following categories of proteins, defined on topological properties: non-bottleneck hubs (NBH), bottleneck hubs (BH), bottleneck non-hubs (BNH) and non-bottleneck non-hubs (NBNH, the largest group by definition).

This project aims at integrating the 4 categories above with the idea of party and date hubs using an interactome for E. coli and a gene expression compendium (since the interaction among two proteins can only take place if the two proteins are expressed at the same moment, one can use gene expression compendia to assign the hubs to the party or date class). The network is used to define the above groups based on the two topological properties (degree, to define hubness, and betweenness centrality, to define bottleneckness).

Let’s start reading E. Coli protein physical links txt file…

rm(list=ls()) # Just good practice to ensure we'll work on a "clean" environment
ECOPPITABLE <- read.table("https://github.com/emanuelecavalleri/partyANDdatePPnetworks/blob/main/511145.protein.physical.links.full.v11.0.txt?raw=true", header=TRUE)

and have a look at it.

head(ECOPPITABLE)

ECOPPITABLE contains experimentally determined interactions. The experiments column indicates some sort of “confidence” in the experiment. We want to have a filter at some value to increase the confidence, and to accomplish that we first take a look at the “trend” of confidence values.

# ECOPPITABLE's dimensions
dim(ECOPPITABLE)
[1] 368774     10
# Confidence values > 0: 
length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 0))])
[1] 6060
# Value of the min confidence value > 0:
min(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 0))])
[1] 46
# Number of values above certain threshold (useful to extract values' "trend") 
c(
  length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 46))]),
  length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 100))]),
  length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 200))]),
  length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 300))]),
  length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 400))]),
  length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 500))]),
  length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 600))]),
  length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 700))]),
  length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 800))])
)
[1] 6036 4650 2554 1778  644  628  628  628  456
# Max confidence value
max(ECOPPITABLE$experiments) 
[1] 896

At a first glimpse, by looking at the number of entries for each subset, we can see number of items reaching a plateau around values > 400, in particular:

# Value of the min confidence value > 400:
min(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 400))])
[1] 406
# Value of the min confidence value > 406:
min(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 406))])
[1] 762

Great gap!

# Number of values above 406 (values ≥ 762) threshold
length(ECOPPITABLE$experiments[(which(ECOPPITABLE$experiments > 406))])
[1] 628

The plateau starts at confidence value = 762; this “empirical” stuff helped me retain an appropriate threshold might be 406/762. But let’s go into further details and make a histogram and a barplot, after the removal of confidence values = 0.

minExp <- 0
# Remove confidence values = 0 while keeping only columns of interest for this project
ECOEXP <- as.data.frame(cbind(ECOPPITABLE$protein1[ECOPPITABLE$experiments>minExp], ECOPPITABLE$protein2[ECOPPITABLE$experiments>minExp], ECOPPITABLE$experiments[ECOPPITABLE$experiments>minExp]))
colnames(ECOEXP) <- c("p1", "p2", "weight")
ECOEXP$weight <- as.numeric(ECOEXP$weight)

barplot(ECOEXP$weight, ylab="Confidence", ylim=c(0,1000))

hist(ECOEXP$weight, xlab="Confidence", xlim=c(0,1000), ylim=c(0,2000), main="Histogram of confidence values", col = c(rep("gray", 9), rep("red", 9)))
legend("topright", c("Confidence values ≤ 406", "Confidence values > 406"), col=c("gray", "red"), lwd=10)

From the barplot we can see that above 400 we have less “density” (due to the 406-762 “gap” we talked before), and from the histogram we confirm our empirical plateau hypothesis. Being said that, we continue our analysis with a > 406 (or, equally, ≥ 762) confidence threshold (may be too high/have too little interactions? Results with a lower threshold showed similar results, but with a higher computational complexity).

minExp <- 406
# Remove confidence values > 406 while keeping only columns of interest for this project
ECOEXP <- as.data.frame(cbind(ECOPPITABLE$protein1[ECOPPITABLE$experiments>minExp], ECOPPITABLE$protein2[ECOPPITABLE$experiments>minExp], ECOPPITABLE$experiments[ECOPPITABLE$experiments>minExp]))
colnames(ECOEXP) <- c("p1", "p2", "weight")
ECOEXP$weight <- as.numeric(ECOEXP$weight)

Below, we also define a much larger network obtained by transferring experimental information from other species (experiments_transferred column involved here). As above, we filter it to retain values for which confidence is relatively high, so let’s have a look at the trend.

minExp <- 0
# Remove confidence values = 0 while keeping only columns of interest for this project
ECOEXP_TRANSF <- as.data.frame(cbind(ECOPPITABLE$protein1[ECOPPITABLE$experiments_transferred>minExp], ECOPPITABLE$protein2[ECOPPITABLE$experiments_transferred>minExp], ECOPPITABLE$experiments_transferred[ECOPPITABLE$experiments_transferred>minExp]))
colnames(ECOEXP_TRANSF) <- c("p1", "p2", "weight")
ECOEXP_TRANSF$weight <- as.numeric(ECOEXP_TRANSF$weight)

# Confidence values > 0:
length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 0))])
[1] 125894
# Value of the min confidence value > 0:
min(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 0))])
[1] 45
# Number of values above certain threshold (useful to extract value's "trend") 
c(
  length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 45))]),
  length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 100))]),
  length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 200))]),
  length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 300))]),
  length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 400))]),
  length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 500))]),
  length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 600))]),
  length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 700))]),
  length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 800))]),
  length(ECOEXP_TRANSF$weight[(which(ECOEXP_TRANSF$weight > 900))])
)
 [1] 125890  92036  16020   9294   6122   5182   4930   4742   4142   3138
# Max confidence value
max(ECOEXP_TRANSF$weight) 
[1] 999

And then, as previously done, we make a barplot and a histogram to help us.

barplot(ECOEXP_TRANSF$weight, ylab="Confidence", ylim=c(0,1000))

hist(ECOEXP_TRANSF$weight, xlab="Confidence", xlim=c(0,1000), ylim=c(0,60000), main="Histogram of confidence values", col = c(rep("gray", 9), rep("red", 11)))

Which is the value for an appropriate threshold?

tail(table(ECOEXP_TRANSF$weight), n=300)

 396  397  398  399  400  401  402  403  404  405  406  407  408  409  410  411  412  413  414  415  416  417  418  419 
  48   24    8   12   32   20   18   18   36   16   20   34    8    2    2    2    2   26   20    8    4   10    6   48 
 420  421  423  424  425  427  428  429  430  431  432  433  434  435  443  448  449  450  451  455  456  457  459  465 
   6    4    2    6    6   62   16   12   18  204   24   38   10   10   82   38    2    4    2    2    2   40    2    4 
 466  468  469  470  473  474  477  481  504  506  507  508  509  510  511  513  520  524  525  532  534  537  538  543 
   4    2   26    2    2    2    4    2    2    4    4   32   10    2   16    2    4    2    2    2    2    2    2    6 
 546  550  557  561  562  563  564  565  566  568  570  572  573  578  583  584  586  591  593  595  597  598  601  607 
   2    2    2    2    4    2    4   12    4    4    2    2    6    8    2    8    2   80    2    4    2    2    4    2 
 608  609  613  622  624  635  640  642  644  645  650  652  654  660  662  663  668  669  671  672  682  685  689  693 
   4    2    6    6    2    2    4    2    4    6    4    4    2    6    4   92    2    2    2    4    2    2    2    2 
 694  695  696  697  698  701  702  704  706  712  715  728  729  730  731  745  754  764  768  771  776  781  782  783 
   2    2    4    2    4    2  120    2    6    2    8    4    2    4    2    4    2    4    2   12    4    2    2    4 
 785  787  790  791  792  793  794  795  796  798  800  801  802  804  806  807  808  812  814  816  819  822  825  827 
   2    2    2   20  364    6    4    6    2    2    2    6   12    2    2    2    8    8    4    2    2    4    2    4 
 829  837  838  839  840  841  842  843  844  845  846  847  848  850  852  853  855  857  860  861  863  864  865  866 
   6   30   74   26    4    2    8   16    6    8   20    4   14    4   10    2    6    2    2   14    6   34   50   12 
 867  868  869  870  871  873  874  876  877  878  879  880  881  882  884  885  886  888  889  891  892  893  895  896 
   2   22    2    6    4    8    4    2    4   32  102   40    6   14   28    4   42    2    4   84   10    4    2    2 
 897  900  901  902  904  905  907  908  909  910  911  913  914  915  916  917  918  919  920  921  922  923  924  925 
  72   84    6    2    8    4   70   22   18    2    6    2    2    6    4   12   12   12   14   72 1498    8    2    4 
 926  927  928  932  934  936  937  938  939  941  944  945  948  949  950  951  952  953  954  955  956  957  959  960 
   2   14    2    4    2   14    2    2    2   20    2    2    2    2    4   42  258   16   22   18   10    2   12   14 
 961  962  963  964  965  966  967  968  969  970  971  972  973  974  975  976  977  978  979  981  983  985  986  987 
  14    2   14    6   10    8   40   10    4   48   26   24   22   18   22   42  308    6   34    2    6    6    8   24 
 988  989  990  991  992  993  994  995  996  997  998  999 
   8   16    6    2    2   24   16    4    8    4   14   74 

I’ll keep values > 448 (but I retain keeping values ≥ 792 wouldn’t be an error since we have very little values between 448 and 792, similarly to the previous analysis when we talked about the 406-762 “gap”).

minExp <- 448
# Remove confidence values > 448 while keeping only columns of interest for this project
ECOEXP_TRANSF <- as.data.frame(cbind(ECOPPITABLE$protein1[ECOPPITABLE$experiments_transferred>minExp], ECOPPITABLE$protein2[ECOPPITABLE$experiments_transferred>minExp], ECOPPITABLE$experiments_transferred[ECOPPITABLE$experiments_transferred>minExp]))
colnames(ECOEXP_TRANSF) <- c("p1", "p2", "weight")
ECOEXP_TRANSF$weight <- as.numeric(ECOEXP_TRANSF$weight)

For the moment, let’s focus on the network with experimentally verified interactions only.

library(igraph)
GEXP <- graph.data.frame(ECOEXP)

And extract connected components, also having a look at the graph using Cytoscape.

CC <- components(GEXP)
# How many?
length(unique(CC$membership))
[1] 80
we <- get.edge.attribute(GEXP,"weight")
library(RCy3)
library(plyr)
cytoscapePing() # Note that Cytoscape must be installed and run to ping it
You are connected to Cytoscape!
createNetworkFromIgraph(GEXP,new.title='GEXP')
Loading data...

Applying default style...

Applying preferred layout...
networkSUID 
        124 

Alternatively, we can do the above for ECOEXP_TRANSF, getting a much denser (more connected) network. We’ll use the last mentioned network for further analysis.

GEXP_TRANSF <- graph.data.frame(ECOEXP_TRANSF)
CCT <- components(GEXP_TRANSF)
# How many?
length(unique(CCT$membership))
[1] 79
weT <- get.edge.attribute(GEXP_TRANSF,"weight")
# To filter it (we won't need to do it because we have already filtered low confidence values):
# GEXP_TRANSF <- delete_edges(GEXP_TRANSF, edges = which(weT < minExp))
# CCT <- components(GEXP_TRANSF) 
createNetworkFromIgraph(GEXP_TRANSF,new.title='GEXP_TRANSF')
Loading data...

Applying default style...

Applying preferred layout...
networkSUID 
       5388 

To identify non-bottleneck hubs and bottleneck hubs we calculate the betweenness centrality (high value == bottleneck).

BET <- betweenness(GEXP_TRANSF, directed=FALSE)
hist(BET)

As they did in papers, we simply define bottlenecks on the basis of the quantile.

# 0.9 threshold to consider a protein a bottleneck in the PPI
BET_TAU <- quantile(BET, 0.9)
GEXP_TRANSF_DEG <- igraph::degree(GEXP_TRANSF)

Then we define HUBS.

# 0.9 threshold to consider a protein a hub in the PPI
DEG_TAU <- quantile(GEXP_TRANSF_DEG, 0.9)

To select bottleneck-hubs (BH) we combine the thresholds to identify a set of proteins fulfilling both.

BH <- V(GEXP_TRANSF)$name[BET>=BET_TAU & GEXP_TRANSF_DEG>=DEG_TAU]

Select non-bottleneck hubs (NBH):

NBH <- V(GEXP_TRANSF)$name[BET<BET_TAU & GEXP_TRANSF_DEG>=DEG_TAU]

Select bottleneck non-hub (BNH):

BNH <- V(GEXP_TRANSF)$name[BET>=BET_TAU & GEXP_TRANSF_DEG<DEG_TAU]

Select non-bottleneck non hubs NBNH:

NBNH <- V(GEXP_TRANSF)$name[BET<BET_TAU & GEXP_TRANSF_DEG<DEG_TAU]

Check the length of the vectors:

c(
  length(BH), length(NBH), length(BNH), length(NBNH)
)
[1]  13  33  32 369

Non-bottleneck non-hubs (NBNH) are the largest group as said by the very beginning.

In this project, instead of having to do with a list of essential genes such that you can simply calculate the length of the intersection, we need to calculate a correlation coefficient distribution for all the interactors of the proteins within each of the BH and NBH (in this project we focus on hubs). Therefore, at this point we download gene expression levels from a provided gene expression compendium for E. coli, then we’ll match protein names here in the graph and in the compendium.

load(url("https://github.com/emanuelecavalleri/partyANDdatePPnetworks/blob/main/Ecoli_compendium.RData?raw=true")) # From now on we'll focus on ZL2 matrix, but we have 3 different versions of a gene expression compendium for E. coli (we could've used ALL_FINAL_Nreads and ALL_FINAL_TPM too). Moreover, we don’t care on conditions (columns of the matrices) in this project

For instance, to have an idea about the content of the matrix, here we report the 6 first conditions’ gene expression levels for the entry b3065, which is a small subunit ribosomal protein belonging to the bacterial ribosomal protein bS21 family also known as “rpsU”.

head(ZL2["b3065",])
 DRR091867  DRR091875  DRR091882  DRR100424  DRR100428 ERR1025366 
 1.9681146  0.9748877  0.2629133  0.7247111  1.6982523 -0.2744939 

For the sake of completeness here we add STRING and AlphaFold entries relative to b3065/rpsU.

STRING

AlphaFold

We are interested in how much the interactors are correlated; before the loop to calculate the pearsons for each member of the bottleneck hub (BH) group, we define:

fixed_intervals <- seq(-1.05, 1.05, .1)
allpearsonsBH <- matrix(0, ncol=length(fixed_intervals)-1, nrow=length(BH))

Now iterate over the BH:

for(i in 1:length(BH)){
  # Neighbor genes such that we can extract the corresponding rows
  # from the compendium 
  hub_interactors <- neighborhood(GEXP_TRANSF,nodes=BH[i])[[1]]
  # BH[i] is the first in the hub_interactors list of interactors
  # extracted with neighborhood, therefore it is in first row;
  # we are interested in the correlation of interactors of BH[i]
  # when BH[i] is "present", therefore:
  match <- match(names(hub_interactors), rownames(ZL2))
  extractedrows <- ZL2[match,]
  bhi_expressed <- which(extractedrows[1,] > mean(extractedrows[1,]))
  extractedrows <- extractedrows[,bhi_expressed]
  # Remove the hub under analysis:
  extractedrows <- extractedrows[-1,]
  # Calculate a matrix of correlation of all proteins interacting
  # with BH[i] vs themselves in all combinations:
  pearsons <- cor(t(extractedrows))
  # Additionally we treat all of them at once, we transform it into a vector
  pearsons <- pearsons[upper.tri(pearsons)]
  # Now we store the distribution of pearsons for each member 
  # of the category (here BH) and then put them together;
  # this can be done by putting all pearson values together for all members
  # of a group and then plot histograms.
  # In doing so however, hubs with larger number of interactors will get more weight.
  par(mfrow=c(1,2)) # Setting the plotting area into a 1*2 array
  if(i >=1 && i <= 3){
    # We'll show you only the first 3 plots for ease of visualization.
    # To give the same weight to the distribution of pearsons value for different hubs:
    h <- hist(pearsons, breaks=fixed_intervals)
    # h$counts/sum(h$counts) and h$mids indicates the middle point of each interval.
    # Then, within the loop, we calculate the above histogram
    plot(h$mids, h$counts/sum(h$counts))
  }
  else
    h <- hist(pearsons, breaks=fixed_intervals, plot=FALSE)
  # and store pearsons correlation coefficients:
  allpearsonsBH[i,] <- h$counts/sum(h$counts)
}

At the end we have allpearsonsBH populated by the values of all members of the group. Are all BH similar/different for the way their targets are correlated?

library(pheatmap)
colnames(allpearsonsBH) <- h$mids
pheatmap(allpearsonsBH, cluster_cols = FALSE)

For party hubs most interactors should be coexpressed at the same time,: we notice a peak on the right (the previous choice of a high threshold highlights this fact).
Conversely, date hubs interact with different interactors at different times, therefore the distribution of correlations among the interactors should be more flat or with several peaks.

allpearsonsNBH <- matrix(0, ncol=length(fixed_intervals)-1, nrow=length(NBH))
for(i in 1:length(NBH)){
  hub_interactors <- neighborhood(GEXP_TRANSF,nodes=NBH[i])[[1]]
  match <- match(names(hub_interactors), rownames(ZL2))
  extractedrows <- ZL2[match,]
  nbhi_expressed <- which(extractedrows[1,] > mean(extractedrows[1,]))
  extractedrows <- extractedrows[,nbhi_expressed]
  extractedrows <- extractedrows[-1,]
  pearsons <- cor(t(extractedrows))
  pearsons <- pearsons[upper.tri(pearsons)]
  par(mfrow=c(1,2))
  if(i >= 1 && i <= 3){
    h <- hist(pearsons, breaks=fixed_intervals)
    plot(h$mids, h$counts/sum(h$counts))
  }
  else
    h <- hist(pearsons, breaks=fixed_intervals, plot=FALSE)
  allpearsonsNBH[i,] <- h$counts/sum(h$counts)
}

colnames(allpearsonsNBH) <- h$mids
pheatmap(allpearsonsNBH, cluster_cols = FALSE)

We can confirm our hypothesis: we can identify peaks in the heatmap and a more “scattered” plot. The fact that several peaks are present may be an indication of multiple complexes formed by the hub and also of many different interactions with one or a few partners at a time.

Let’s now see if there is some inner structure by using some dimensionality reduction technique such as UMAP and PCA on BH and NBH groups: we’ll focus on UMAP first.

library(uwot)
UBH <- umap(allpearsonsBH, n_components = 3, n_neighbors = 2)
library(rgl)
options(rgl.useNULL = TRUE)
plot3d(x=UBH[,1], y=UBH[,2], z=UBH[,3], col="red")
rglwidget()
UNBH <- umap(allpearsonsNBH, n_components = 3)
plot3d(x=UNBH[,1], y=UNBH[,2], z=UNBH[,3], col="green")
rglwidget()

And what if we join the allpearsonsBH and allpearsonsNBH and do the same? We can also color BH and NBH items differently to see if they group together.

allpearsons <- rbind(allpearsonsBH, allpearsonsNBH)
U <- umap(allpearsons, n_components = 3)
plot3d(x=U[,1], y=U[,2], z=U[,3], col = c(rep("red", length(BH)), rep("green", length(NBH))))
legend3d("topright", legend = c('BH', 'NBH'), pch = 16, col = c("red", "green"), cex=1, inset=c(0.02))
rglwidget()

We can recognize three groups of interest in the space. Focusing on BH points we can notice that the 13 points belonging to that category are not all grouped together, but we can see that the majority are within a precise region of the 3D space and that the three/four outside the “condensed” region seem to follow a precise trajectory toward the other two NBH groups, so maybe a sign of similar behavior. In other words, BH points are not isolated in the space, but within regions also populated by NBH points (at least one BH point in any NBH region).

Now let’s focus onto PCA technique.

PCA <- prcomp(allpearsons)
scores = as.data.frame(PCA$x)
library(ggplot2)
ggplot(data = scores, aes(x = PC1, y = PC2, label = rownames(scores))) +
  geom_hline(yintercept = 0, colour = "gray65") +
  geom_vline(xintercept = 0, colour = "gray65") +
  geom_text(colour = c(rep("red", length(BH)), rep("green", length(NBH))), alpha = 0.8, size = 4)

PCA makes it even clearer definitely confirming our results previously obtained: red points (coming from the BH group), except for points 2 and 3 and if you want 13 (similarly to the 3/4 points distant from the most populated group in UMAP 3D plot), tend to group together, while other ones (belonging to the NBH group) tend to be sparser (curiously similar to the fact that previously we obtained a more “scattered” heatmap).

Session infos:

cytoscapeVersionInfo()
      apiVersion cytoscapeVersion 
            "v1"          "3.9.0" 
sessionInfo()
R version 4.0.4 (2021-02-15)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Big Sur 10.16

Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] it_IT.UTF-8/it_IT.UTF-8/it_IT.UTF-8/C/it_IT.UTF-8/it_IT.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] ggplot2_3.3.5   rgl_0.108.3     uwot_0.1.11     Matrix_1.4-0    pheatmap_1.0.12 plyr_1.8.6      RCy3_2.10.2    
[8] igraph_1.2.10  

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.7          lattice_0.20-45     FNN_1.1.3           assertthat_0.2.1    digest_0.6.29      
 [6] utf8_1.2.2          RSpectra_0.16-0     mime_0.12           R6_2.5.1            stats4_4.0.4       
[11] evaluate_0.14       httr_1.4.2          pillar_1.6.4        rlang_0.4.12        curl_4.3.2         
[16] irlba_2.3.5         jquerylib_0.1.4     R.utils_2.11.0      R.oo_1.24.0         rmarkdown_2.11     
[21] labeling_0.4.2      stringr_1.4.0       htmlwidgets_1.5.4   munsell_0.5.0       compiler_4.0.4     
[26] xfun_0.29           pkgconfig_2.0.3     BiocGenerics_0.36.1 htmltools_0.5.2     tidyselect_1.1.1   
[31] tibble_3.1.6        XML_3.99-0.8        fansi_0.5.0         crayon_1.4.2        dplyr_1.0.7        
[36] withr_2.4.3         R.methodsS3_1.8.1   grid_4.0.4          jsonlite_1.7.2      gtable_0.3.0       
[41] lifecycle_1.0.1     DBI_1.1.2           magrittr_2.0.1      scales_1.1.1        graph_1.68.0       
[46] stringi_1.7.6       farver_2.1.0        bslib_0.3.1         ellipsis_0.3.2      vctrs_0.3.8        
[51] generics_0.1.1      RColorBrewer_1.1-2  tools_4.0.4         RJSONIO_1.3-1.6     glue_1.6.0         
[56] purrr_0.3.4         parallel_4.0.4      fastmap_1.1.0       yaml_2.2.1          colorspace_2.0-2   
[61] knitr_1.37          sass_0.4.0         
LS0tCnRpdGxlOiAiUGFydHkgYW5kIGRhdGUgaHVicyBpbiBwcm90ZWluLXByb3RlaW4gaW50ZXJhY3Rpb24gbmV0d29ya3MiCnN1YnRpdGxlOiAiQWR2YW5jZWQgZ2Vub21pY3MnIFVOSU1JIHByb2plY3QgKEFZIDIwMjEvMjAyMikiCmF1dGhvcjoKICAtIG5hbWU6ICJFbWFudWVsZSBDYXZhbGxlcmkgKG1hdHJpY3VsYXRpb24gbnVtYmVyOiA5ODU4ODgpIgogICAgYWZmaWxpYXRpb246ICJbVW5pdmVyc2l0w6AgZGVnbGkgU3R1ZGkgZGkgTWlsYW5vXShodHRwczovL3d3dy51bmltaS5pdC9lbikiCm91dHB1dDogaHRtbF9ub3RlYm9vayAKLS0tCgpUaGlzIGlzIG15IEFkdmFuY2VkIGdlbm9taWNzJyBwcm9qZWN0IGZvciB0aGUgQVkgMjAyMS8yMDIyLiBEYXRhIGFuZCBjb2RlIGNhbiBiZSByZXRyaWV2ZWQgZnJvbSB0aGUgZm9sbG93aW5nIFtHaXRIdWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9lbWFudWVsZWNhdmFsbGVyaS9wYXJ0eUFORGRhdGVQUG5ldHdvcmtzKSBsaW5rLgoKSW4gcHJvdGVpbi1wcm90ZWluIGludGVyYWN0aW9uIChbUFBJXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Qcm90ZWluJUUyJTgwJTkzcHJvdGVpbl9pbnRlcmFjdGlvbikgZnJvbSBub3cgb24pIG5ldHdvcmtzICh0aGVyZWZvcmUgcHJvdGVpbnMgdGhhdCBpbnRlcmFjdCB3aXRoIG1hbnkgb3RoZXIgcHJvdGVpbnMpIHdlIGRpc3Rpbmd1aXNoIFtodWJzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JbnRlcmFjdG9tZSNIdWJzKSAoaGlnaGx5IGNvbm5lY3RlZCBub2Rlcy9wcm90ZWlucykgaW50byBwYXJ0eSBhbmQgZGF0ZSBjYXRlZ29yaWVzLiBUaGlzIGRpZmZlcmVudGlhdGlvbiBjb21lcyBmcm9tIGFuIFthbmFseXNpc10oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9uYXR1cmUwMjU1NSkgKEhhbiBldCBhbC4pIHdoZXJlIGl0IHdhcyBzaG93biB0aGF0IGh1YnMgb2YgdGhlIFBQSSBuZXR3b3JrIGNhbiBiZSBhc3NpZ25lZCB0byB0d28gZGlmZmVyZW50IGNhdGVnb3JpZXM6XArCtyBIdWJzIHRoYXQgaW50ZXJhY3Qgd2l0aCBtYW55IHBhcnRuZXJzIGF0IHRoZSBzYW1lIG1vbWVudCAocGFydHkgaHVicyksICB3aGljaCBhbHNvIGNvbm5lY3QgcHJvdGVpbnMgd2l0aGluIGZ1bmN0aW9uYWwgbW9kdWxlcyBzdWNoIGFzIHByb3RlaW4gY29tcGxleGVzLiBQYXJ0eSBodWJzIGNvbXBvbmVudHMnIGV4cHJlc3Npb24gaXMgY29ycmVsYXRlZCB3aXRoIGl0cyBpbnRlcmFjdGlvbiBwYXJ0bmVycy5cCsK3IEh1YnMgdGhhdCBoYXZlIG1hbnkgdGFyZ2V0cywgYnV0IGludGVyYWN0IHdpdGggb25seSBvbmUgb3IgYSBmZXcgb2YgdGhlbSBhdCBhbnkgbW9tZW50IChkYXRlIGh1YnMpLiBJbiBjb250cmFzdCB0byBwYXJ0eSBodWJzLCBkYXRlIGh1YnMgZG8gbm90IGV4aGliaXQgc3VjaCBhIGNvcnJlbGF0aW9uIGFuZCBhcHBlYXIgdG8gY29ubmVjdCBkaWZmZXJlbnQgZnVuY3Rpb25hbCBtb2R1bGVzLlwKQSBwb3B1bGFyIFBQSSBuZXR3b3JrcyBmdW5jdGlvbmFsIGVucmljaG1lbnQgYW5hbHlzaXMgdG9vbCBpcyBbU1RSSU5HXShodHRwczovL3N0cmluZy1kYi5vcmcvKS4KClRoZSB2YWxpZGl0eSBvZiB0aGUgZGF0ZSBodWIvcGFydHkgaHViIGRpc3RpbmN0aW9uIHdhcyBkaXNwdXRlZCwgdGhlIGNvbmNlcHQgbWlnaHQgbm90IGJlIGFzIGdlbmVyYWwgYXMgaXQgc2VlbWVkIHdoZW4gdGhlIG9yaWdpbmFsIHB1YmxpY2F0aW9uIHdhcyBwcmVzZW50ZWQuIEluIHBhcnRpY3VsYXIsIGluIHRoaXMgW3BhcGVyXShodHRwczovL2RvaS5vcmcvMTAuMTM3MS9qb3VybmFsLnBjYmkuMTAwMDgxNyksIHRoZSBhdXRob3JzIHNob3dlZCB0aGF0IHRoZSByZXBvcnRlZCBpbXBvcnRhbmNlIG9mIGRhdGUgaHVicyB0byBuZXR3b3JrIGNvbm5lY3Rpdml0eSBjYW4gaW4gZmFjdCBiZSBhdHRyaWJ1dGVkIHRvIGEgdGlueSBzdWJzZXQgb2YgdGhlbS5cClRoZSBkYXRlL3BhcnR5IGRpc3RpbmN0aW9uIHdhcyBvcmlnaW5hbGx5IG1vdGl2YXRlZCBieSBhbiBhcHByb3hpbWF0ZWx5IGJpbW9kYWwgZGlzdHJpYnV0aW9uIG9mIGh1YiBjby1leHByZXNzaW9uLCBidXQgdGhpcyBmZWF0dXJlIGlzIG5vdCBhbHdheXMgcm9idXN0IHRvIG1ldGhvZG9sb2dpY2FsIGNoYW5nZXMuIEFkZGl0aW9uYWxseSwgdG9wb2xvZ2ljYWwgcHJvcGVydGllcyBvZiBodWJzIGRvIG5vdCBpbiBnZW5lcmFsIGNvcnJlbGF0ZSB3aXRoIGNvLWV4cHJlc3Npb24uIEFjY29yZGluZyB0byB0aGUgcGFwZXIsICp0aGlua2luZyBpbiB0ZXJtcyBvZiBhIGRhdGUvcGFydHkgZGljaG90b215IGZvciBodWJzIGluIHByb3RlaW4gaW50ZXJhY3Rpb24gbmV0d29ya3MgaXMgbm90IG1lYW5pbmdmdWwsIGFuZCBpdCBtaWdodCBiZSBtb3JlIHVzZWZ1bCB0byBjb25jZWl2ZSBvZiByb2xlcyBmb3IgcHJvdGVpbi1wcm90ZWluIGludGVyYWN0aW9ucyByYXRoZXIgdGhhbiBmb3IgaW5kaXZpZHVhbCBwcm90ZWlucyouCgpUaGlzIHByb2plY3QgaXMgYmFzZWQgb24gdGhlIGZhY3QgdGhhdCB0aGUgcGFydHkgYW5kIGRhdGUgaHViIGNvbmNlcHQgbWF5IGJlIGludGVyZXN0aW5nIHRvIGJlIG1lcmdlZCB3aXRoIGFub3RoZXIgdG9wb2xvZ2ljYWwgcHJvcGVydHkgb2Ygbm9kZXMsIFtiZXR3ZWVubmVzcyBjZW50cmFsaXR5XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9DZW50cmFsaXR5I0JldHdlZW5uZXNzX2NlbnRyYWxpdHkpLCB0aGF0IHdlIGNhbiB1c2UgdG8gaW50cm9kdWNlIHRoZSBib3R0bGVuZWNrIGNvbmNlcHQgaW50byB0aGUgcGFydHkvZGF0ZSBodWJzIGNvbmNlcHR1YWxpemF0aW9uLiBbKkJldHdlZW5uZXNzIChpLmUuLCDigJxib3R0bGVuZWNrLW5lc3PigJ0pIGlzIGEgbXVjaCBtb3JlIHNpZ25pZmljYW50IGluZGljYXRvciBvZiBlc3NlbnRpYWxpdHkgdGhhbiBkZWdyZWUgKGkuZS4sIOKAnGh1Yi1uZXNz4oCdKS4gRnVydGhlcm1vcmUsIGJvdHRsZW5lY2tzIGNvcnJlc3BvbmQgdG8gdGhlIGR5bmFtaWMgY29tcG9uZW50cyBvZiB0aGUgaW50ZXJhY3Rpb24gbmV0d29ya+KAlHRoZXkgYXJlIHNpZ25pZmljYW50bHkgbGVzcyB3ZWxsIGNvZXhwcmVzc2VkIHdpdGggdGhlaXIgbmVpZ2hib3JzIHRoYW4gbm9uLWJvdHRsZW5lY2tzLCBpbXBseWluZyB0aGF0IGV4cHJlc3Npb24gZHluYW1pY3MgaXMgd2lyZWQgaW50byB0aGUgbmV0d29yayB0b3BvbG9neS4qXShodHRwczovL2RvaS5vcmcvMTAuMTM3MS9qb3VybmFsLnBjYmkuMDAzMDA1OS4pCgpUaGVyZWZvcmUsIGNvbWJpbmluZyBodWJzIGFuZCBib3R0bGVuZWNrcywgd2UgY2FuIGRlZmluZSBmb3IgaW5zdGFuY2UgdGhlIGZvbGxvd2luZyBjYXRlZ29yaWVzIG9mIHByb3RlaW5zLCBkZWZpbmVkIG9uIHRvcG9sb2dpY2FsIHByb3BlcnRpZXM6IG5vbi1ib3R0bGVuZWNrIGh1YnMgKE5CSCksIGJvdHRsZW5lY2sgaHVicyAoQkgpLCBib3R0bGVuZWNrIG5vbi1odWJzIChCTkgpIGFuZCBub24tYm90dGxlbmVjayBub24taHVicyAoTkJOSCwgdGhlIGxhcmdlc3QgZ3JvdXAgYnkgZGVmaW5pdGlvbikuIAoKIVtdKHBjYmkuMDAzMDA1OS5nMDAxLlBOR19MLnBuZykKClRoaXMgcHJvamVjdCBhaW1zIGF0IGludGVncmF0aW5nIHRoZSA0IGNhdGVnb3JpZXMgYWJvdmUgd2l0aCB0aGUgaWRlYSBvZiBwYXJ0eSBhbmQgZGF0ZSBodWJzIHVzaW5nIGFuIGludGVyYWN0b21lIGZvciBFLiBjb2xpIGFuZCBhIGdlbmUgZXhwcmVzc2lvbiBjb21wZW5kaXVtIChzaW5jZSB0aGUgaW50ZXJhY3Rpb24gYW1vbmcgdHdvIHByb3RlaW5zIGNhbiBvbmx5IHRha2UgcGxhY2UgaWYgdGhlIHR3byBwcm90ZWlucyBhcmUgZXhwcmVzc2VkIGF0IHRoZSBzYW1lIG1vbWVudCwgb25lIGNhbiB1c2UgZ2VuZSBleHByZXNzaW9uIGNvbXBlbmRpYSB0byBhc3NpZ24gdGhlIGh1YnMgdG8gdGhlIHBhcnR5IG9yIGRhdGUgY2xhc3MpLiAgVGhlIG5ldHdvcmsgaXMgdXNlZCB0byBkZWZpbmUgdGhlIGFib3ZlIGdyb3VwcyBiYXNlZCBvbiB0aGUgdHdvIHRvcG9sb2dpY2FsIHByb3BlcnRpZXMgKGRlZ3JlZSwgdG8gZGVmaW5lIGh1Ym5lc3MsIGFuZCBiZXR3ZWVubmVzcyBjZW50cmFsaXR5LCB0byBkZWZpbmUgYm90dGxlbmVja25lc3MpLgoKTGV0J3Mgc3RhcnQgcmVhZGluZyBbRS4gQ29saSBwcm90ZWluIHBoeXNpY2FsIGxpbmtzXShodHRwczovL2dpdGh1Yi5jb20vZW1hbnVlbGVjYXZhbGxlcmkvcGFydHlBTkRkYXRlUFBuZXR3b3Jrcy9ibG9iL21haW4vNTExMTQ1LnByb3RlaW4ucGh5c2ljYWwubGlua3MuZnVsbC52MTEuMC50eHQ/cmF3PXRydWUpIHR4dCBmaWxlLi4uCmBgYHtyfQpybShsaXN0PWxzKCkpICMgSnVzdCBnb29kIHByYWN0aWNlIHRvIGVuc3VyZSB3ZSdsbCB3b3JrIG9uIGEgImNsZWFuIiBlbnZpcm9ubWVudApFQ09QUElUQUJMRSA8LSByZWFkLnRhYmxlKCJodHRwczovL2dpdGh1Yi5jb20vZW1hbnVlbGVjYXZhbGxlcmkvcGFydHlBTkRkYXRlUFBuZXR3b3Jrcy9ibG9iL21haW4vNTExMTQ1LnByb3RlaW4ucGh5c2ljYWwubGlua3MuZnVsbC52MTEuMC50eHQ/cmF3PXRydWUiLCBoZWFkZXI9VFJVRSkKYGBgCmFuZCBoYXZlIGEgbG9vayBhdCBpdC4KYGBge3J9CmhlYWQoRUNPUFBJVEFCTEUpCmBgYAoqRUNPUFBJVEFCTEUqIGNvbnRhaW5zIGV4cGVyaW1lbnRhbGx5IGRldGVybWluZWQgaW50ZXJhY3Rpb25zLiBUaGUgKmV4cGVyaW1lbnRzKiBjb2x1bW4gaW5kaWNhdGVzIHNvbWUgc29ydCBvZiAiY29uZmlkZW5jZSIgaW4gdGhlIGV4cGVyaW1lbnQuIFdlIHdhbnQgdG8gaGF2ZSBhIGZpbHRlciBhdCBzb21lIHZhbHVlIHRvIGluY3JlYXNlIHRoZSBjb25maWRlbmNlLCBhbmQgdG8gYWNjb21wbGlzaCB0aGF0IHdlIGZpcnN0IHRha2UgYSBsb29rIGF0IHRoZSAidHJlbmQiIG9mIGNvbmZpZGVuY2UgdmFsdWVzLgpgYGB7cn0KIyBFQ09QUElUQUJMRSdzIGRpbWVuc2lvbnMKZGltKEVDT1BQSVRBQkxFKQojIENvbmZpZGVuY2UgdmFsdWVzID4gMDogCmxlbmd0aChFQ09QUElUQUJMRSRleHBlcmltZW50c1sod2hpY2goRUNPUFBJVEFCTEUkZXhwZXJpbWVudHMgPiAwKSldKQojIFZhbHVlIG9mIHRoZSBtaW4gY29uZmlkZW5jZSB2YWx1ZSA+IDA6Cm1pbihFQ09QUElUQUJMRSRleHBlcmltZW50c1sod2hpY2goRUNPUFBJVEFCTEUkZXhwZXJpbWVudHMgPiAwKSldKQojIE51bWJlciBvZiB2YWx1ZXMgYWJvdmUgY2VydGFpbiB0aHJlc2hvbGQgKHVzZWZ1bCB0byBleHRyYWN0IHZhbHVlcycgInRyZW5kIikgCmMoCiAgbGVuZ3RoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzWyh3aGljaChFQ09QUElUQUJMRSRleHBlcmltZW50cyA+IDQ2KSldKSwKICBsZW5ndGgoRUNPUFBJVEFCTEUkZXhwZXJpbWVudHNbKHdoaWNoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzID4gMTAwKSldKSwKICBsZW5ndGgoRUNPUFBJVEFCTEUkZXhwZXJpbWVudHNbKHdoaWNoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzID4gMjAwKSldKSwKICBsZW5ndGgoRUNPUFBJVEFCTEUkZXhwZXJpbWVudHNbKHdoaWNoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzID4gMzAwKSldKSwKICBsZW5ndGgoRUNPUFBJVEFCTEUkZXhwZXJpbWVudHNbKHdoaWNoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzID4gNDAwKSldKSwKICBsZW5ndGgoRUNPUFBJVEFCTEUkZXhwZXJpbWVudHNbKHdoaWNoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzID4gNTAwKSldKSwKICBsZW5ndGgoRUNPUFBJVEFCTEUkZXhwZXJpbWVudHNbKHdoaWNoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzID4gNjAwKSldKSwKICBsZW5ndGgoRUNPUFBJVEFCTEUkZXhwZXJpbWVudHNbKHdoaWNoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzID4gNzAwKSldKSwKICBsZW5ndGgoRUNPUFBJVEFCTEUkZXhwZXJpbWVudHNbKHdoaWNoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzID4gODAwKSldKQopCiMgTWF4IGNvbmZpZGVuY2UgdmFsdWUKbWF4KEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzKSAKYGBgCkF0IGEgZmlyc3QgZ2xpbXBzZSwgYnkgbG9va2luZyBhdCB0aGUgbnVtYmVyIG9mIGVudHJpZXMgZm9yIGVhY2ggc3Vic2V0LCB3ZSBjYW4gc2VlIG51bWJlciBvZiBpdGVtcyByZWFjaGluZyBhIHBsYXRlYXUgYXJvdW5kIHZhbHVlcyA+IDQwMCwgaW4gcGFydGljdWxhcjoKYGBge3J9CiMgVmFsdWUgb2YgdGhlIG1pbiBjb25maWRlbmNlIHZhbHVlID4gNDAwOgptaW4oRUNPUFBJVEFCTEUkZXhwZXJpbWVudHNbKHdoaWNoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzID4gNDAwKSldKQojIFZhbHVlIG9mIHRoZSBtaW4gY29uZmlkZW5jZSB2YWx1ZSA+IDQwNjoKbWluKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzWyh3aGljaChFQ09QUElUQUJMRSRleHBlcmltZW50cyA+IDQwNikpXSkKYGBgCkdyZWF0IGdhcCEKYGBge3J9CiMgTnVtYmVyIG9mIHZhbHVlcyBhYm92ZSA0MDYgKHZhbHVlcyDiiaUgNzYyKSB0aHJlc2hvbGQKbGVuZ3RoKEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzWyh3aGljaChFQ09QUElUQUJMRSRleHBlcmltZW50cyA+IDQwNikpXSkKYGBgClRoZSBwbGF0ZWF1IHN0YXJ0cyBhdCBjb25maWRlbmNlIHZhbHVlID0gNzYyOyB0aGlzICJlbXBpcmljYWwiIHN0dWZmIGhlbHBlZCBtZSByZXRhaW4gYW4gYXBwcm9wcmlhdGUgdGhyZXNob2xkIG1pZ2h0IGJlIDQwNi83NjIuIEJ1dCBsZXQncyBnbyBpbnRvIGZ1cnRoZXIgZGV0YWlscyBhbmQgbWFrZSBhIGhpc3RvZ3JhbSBhbmQgYSBiYXJwbG90LCBhZnRlciB0aGUgcmVtb3ZhbCBvZiBjb25maWRlbmNlIHZhbHVlcyA9IDAuCmBgYHtyfQptaW5FeHAgPC0gMAojIFJlbW92ZSBjb25maWRlbmNlIHZhbHVlcyA9IDAgd2hpbGUga2VlcGluZyBvbmx5IGNvbHVtbnMgb2YgaW50ZXJlc3QgZm9yIHRoaXMgcHJvamVjdApFQ09FWFAgPC0gYXMuZGF0YS5mcmFtZShjYmluZChFQ09QUElUQUJMRSRwcm90ZWluMVtFQ09QUElUQUJMRSRleHBlcmltZW50cz5taW5FeHBdLCBFQ09QUElUQUJMRSRwcm90ZWluMltFQ09QUElUQUJMRSRleHBlcmltZW50cz5taW5FeHBdLCBFQ09QUElUQUJMRSRleHBlcmltZW50c1tFQ09QUElUQUJMRSRleHBlcmltZW50cz5taW5FeHBdKSkKY29sbmFtZXMoRUNPRVhQKSA8LSBjKCJwMSIsICJwMiIsICJ3ZWlnaHQiKQpFQ09FWFAkd2VpZ2h0IDwtIGFzLm51bWVyaWMoRUNPRVhQJHdlaWdodCkKCmJhcnBsb3QoRUNPRVhQJHdlaWdodCwgeWxhYj0iQ29uZmlkZW5jZSIsIHlsaW09YygwLDEwMDApKQpoaXN0KEVDT0VYUCR3ZWlnaHQsIHhsYWI9IkNvbmZpZGVuY2UiLCB4bGltPWMoMCwxMDAwKSwgeWxpbT1jKDAsMjAwMCksIG1haW49Ikhpc3RvZ3JhbSBvZiBjb25maWRlbmNlIHZhbHVlcyIsIGNvbCA9IGMocmVwKCJncmF5IiwgOSksIHJlcCgicmVkIiwgOSkpKQpsZWdlbmQoInRvcHJpZ2h0IiwgYygiQ29uZmlkZW5jZSB2YWx1ZXMg4omkIDQwNiIsICJDb25maWRlbmNlIHZhbHVlcyA+IDQwNiIpLCBjb2w9YygiZ3JheSIsICJyZWQiKSwgbHdkPTEwKQpgYGAKRnJvbSB0aGUgYmFycGxvdCB3ZSBjYW4gc2VlIHRoYXQgYWJvdmUgNDAwIHdlIGhhdmUgbGVzcyAiZGVuc2l0eSIgKGR1ZSB0byB0aGUgNDA2LTc2MiAiZ2FwIiB3ZSB0YWxrZWQgYmVmb3JlKSwgYW5kIGZyb20gdGhlIGhpc3RvZ3JhbSB3ZSBjb25maXJtIG91ciBlbXBpcmljYWwgcGxhdGVhdSBoeXBvdGhlc2lzLiBCZWluZyBzYWlkIHRoYXQsIHdlIGNvbnRpbnVlIG91ciBhbmFseXNpcyB3aXRoIGEgPiA0MDYgKG9yLCBlcXVhbGx5LCDiiaUgNzYyKSBjb25maWRlbmNlIHRocmVzaG9sZCAobWF5IGJlIHRvbyBoaWdoL2hhdmUgdG9vIGxpdHRsZSBpbnRlcmFjdGlvbnM/IFJlc3VsdHMgd2l0aCBhIGxvd2VyIHRocmVzaG9sZCBzaG93ZWQgc2ltaWxhciByZXN1bHRzLCBidXQgd2l0aCBhIGhpZ2hlciBjb21wdXRhdGlvbmFsIGNvbXBsZXhpdHkpLgpgYGB7cn0KbWluRXhwIDwtIDQwNgojIFJlbW92ZSBjb25maWRlbmNlIHZhbHVlcyA+IDQwNiB3aGlsZSBrZWVwaW5nIG9ubHkgY29sdW1ucyBvZiBpbnRlcmVzdCBmb3IgdGhpcyBwcm9qZWN0CkVDT0VYUCA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKEVDT1BQSVRBQkxFJHByb3RlaW4xW0VDT1BQSVRBQkxFJGV4cGVyaW1lbnRzPm1pbkV4cF0sIEVDT1BQSVRBQkxFJHByb3RlaW4yW0VDT1BQSVRBQkxFJGV4cGVyaW1lbnRzPm1pbkV4cF0sIEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzW0VDT1BQSVRBQkxFJGV4cGVyaW1lbnRzPm1pbkV4cF0pKQpjb2xuYW1lcyhFQ09FWFApIDwtIGMoInAxIiwgInAyIiwgIndlaWdodCIpCkVDT0VYUCR3ZWlnaHQgPC0gYXMubnVtZXJpYyhFQ09FWFAkd2VpZ2h0KQpgYGAKQmVsb3csIHdlIGFsc28gZGVmaW5lIGEgbXVjaCBsYXJnZXIgbmV0d29yayBvYnRhaW5lZCBieSB0cmFuc2ZlcnJpbmcgZXhwZXJpbWVudGFsIGluZm9ybWF0aW9uIGZyb20gb3RoZXIgc3BlY2llcyAoKmV4cGVyaW1lbnRzX3RyYW5zZmVycmVkKiBjb2x1bW4gaW52b2x2ZWQgaGVyZSkuIEFzIGFib3ZlLCB3ZSBmaWx0ZXIgaXQgdG8gcmV0YWluIHZhbHVlcyBmb3Igd2hpY2ggY29uZmlkZW5jZSBpcyByZWxhdGl2ZWx5IGhpZ2gsIHNvIGxldCdzIGhhdmUgYSBsb29rIGF0IHRoZSB0cmVuZC4KYGBge3J9Cm1pbkV4cCA8LSAwCiMgUmVtb3ZlIGNvbmZpZGVuY2UgdmFsdWVzID0gMCB3aGlsZSBrZWVwaW5nIG9ubHkgY29sdW1ucyBvZiBpbnRlcmVzdCBmb3IgdGhpcyBwcm9qZWN0CkVDT0VYUF9UUkFOU0YgPC0gYXMuZGF0YS5mcmFtZShjYmluZChFQ09QUElUQUJMRSRwcm90ZWluMVtFQ09QUElUQUJMRSRleHBlcmltZW50c190cmFuc2ZlcnJlZD5taW5FeHBdLCBFQ09QUElUQUJMRSRwcm90ZWluMltFQ09QUElUQUJMRSRleHBlcmltZW50c190cmFuc2ZlcnJlZD5taW5FeHBdLCBFQ09QUElUQUJMRSRleHBlcmltZW50c190cmFuc2ZlcnJlZFtFQ09QUElUQUJMRSRleHBlcmltZW50c190cmFuc2ZlcnJlZD5taW5FeHBdKSkKY29sbmFtZXMoRUNPRVhQX1RSQU5TRikgPC0gYygicDEiLCAicDIiLCAid2VpZ2h0IikKRUNPRVhQX1RSQU5TRiR3ZWlnaHQgPC0gYXMubnVtZXJpYyhFQ09FWFBfVFJBTlNGJHdlaWdodCkKCiMgQ29uZmlkZW5jZSB2YWx1ZXMgPiAwOgpsZW5ndGgoRUNPRVhQX1RSQU5TRiR3ZWlnaHRbKHdoaWNoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0ID4gMCkpXSkKIyBWYWx1ZSBvZiB0aGUgbWluIGNvbmZpZGVuY2UgdmFsdWUgPiAwOgptaW4oRUNPRVhQX1RSQU5TRiR3ZWlnaHRbKHdoaWNoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0ID4gMCkpXSkKIyBOdW1iZXIgb2YgdmFsdWVzIGFib3ZlIGNlcnRhaW4gdGhyZXNob2xkICh1c2VmdWwgdG8gZXh0cmFjdCB2YWx1ZSdzICJ0cmVuZCIpIApjKAogIGxlbmd0aChFQ09FWFBfVFJBTlNGJHdlaWdodFsod2hpY2goRUNPRVhQX1RSQU5TRiR3ZWlnaHQgPiA0NSkpXSksCiAgbGVuZ3RoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0Wyh3aGljaChFQ09FWFBfVFJBTlNGJHdlaWdodCA+IDEwMCkpXSksCiAgbGVuZ3RoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0Wyh3aGljaChFQ09FWFBfVFJBTlNGJHdlaWdodCA+IDIwMCkpXSksCiAgbGVuZ3RoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0Wyh3aGljaChFQ09FWFBfVFJBTlNGJHdlaWdodCA+IDMwMCkpXSksCiAgbGVuZ3RoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0Wyh3aGljaChFQ09FWFBfVFJBTlNGJHdlaWdodCA+IDQwMCkpXSksCiAgbGVuZ3RoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0Wyh3aGljaChFQ09FWFBfVFJBTlNGJHdlaWdodCA+IDUwMCkpXSksCiAgbGVuZ3RoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0Wyh3aGljaChFQ09FWFBfVFJBTlNGJHdlaWdodCA+IDYwMCkpXSksCiAgbGVuZ3RoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0Wyh3aGljaChFQ09FWFBfVFJBTlNGJHdlaWdodCA+IDcwMCkpXSksCiAgbGVuZ3RoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0Wyh3aGljaChFQ09FWFBfVFJBTlNGJHdlaWdodCA+IDgwMCkpXSksCiAgbGVuZ3RoKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0Wyh3aGljaChFQ09FWFBfVFJBTlNGJHdlaWdodCA+IDkwMCkpXSkKKQojIE1heCBjb25maWRlbmNlIHZhbHVlCm1heChFQ09FWFBfVFJBTlNGJHdlaWdodCkgCmBgYApBbmQgdGhlbiwgYXMgcHJldmlvdXNseSBkb25lLCB3ZSBtYWtlIGEgYmFycGxvdCBhbmQgYSBoaXN0b2dyYW0gdG8gaGVscCB1cy4KYGBge3J9CmJhcnBsb3QoRUNPRVhQX1RSQU5TRiR3ZWlnaHQsIHlsYWI9IkNvbmZpZGVuY2UiLCB5bGltPWMoMCwxMDAwKSkKaGlzdChFQ09FWFBfVFJBTlNGJHdlaWdodCwgeGxhYj0iQ29uZmlkZW5jZSIsIHhsaW09YygwLDEwMDApLCB5bGltPWMoMCw2MDAwMCksIG1haW49Ikhpc3RvZ3JhbSBvZiBjb25maWRlbmNlIHZhbHVlcyIsIGNvbCA9IGMocmVwKCJncmF5IiwgOSksIHJlcCgicmVkIiwgMTEpKSkKYGBgCldoaWNoIGlzIHRoZSB2YWx1ZSBmb3IgYW4gYXBwcm9wcmlhdGUgdGhyZXNob2xkPwpgYGB7cn0KdGFpbCh0YWJsZShFQ09FWFBfVFJBTlNGJHdlaWdodCksIG49MzAwKQpgYGAKSSdsbCBrZWVwIHZhbHVlcyA+IDQ0OCAoYnV0IEkgcmV0YWluIGtlZXBpbmcgdmFsdWVzIOKJpSA3OTIgd291bGRuJ3QgYmUgYW4gZXJyb3Igc2luY2Ugd2UgaGF2ZSB2ZXJ5IGxpdHRsZSB2YWx1ZXMgYmV0d2VlbiA0NDggYW5kIDc5Miwgc2ltaWxhcmx5IHRvIHRoZSBwcmV2aW91cyBhbmFseXNpcyB3aGVuIHdlIHRhbGtlZCBhYm91dCB0aGUgNDA2LTc2MiAiZ2FwIikuCmBgYHtyfQptaW5FeHAgPC0gNDQ4CiMgUmVtb3ZlIGNvbmZpZGVuY2UgdmFsdWVzID4gNDQ4IHdoaWxlIGtlZXBpbmcgb25seSBjb2x1bW5zIG9mIGludGVyZXN0IGZvciB0aGlzIHByb2plY3QKRUNPRVhQX1RSQU5TRiA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKEVDT1BQSVRBQkxFJHByb3RlaW4xW0VDT1BQSVRBQkxFJGV4cGVyaW1lbnRzX3RyYW5zZmVycmVkPm1pbkV4cF0sIEVDT1BQSVRBQkxFJHByb3RlaW4yW0VDT1BQSVRBQkxFJGV4cGVyaW1lbnRzX3RyYW5zZmVycmVkPm1pbkV4cF0sIEVDT1BQSVRBQkxFJGV4cGVyaW1lbnRzX3RyYW5zZmVycmVkW0VDT1BQSVRBQkxFJGV4cGVyaW1lbnRzX3RyYW5zZmVycmVkPm1pbkV4cF0pKQpjb2xuYW1lcyhFQ09FWFBfVFJBTlNGKSA8LSBjKCJwMSIsICJwMiIsICJ3ZWlnaHQiKQpFQ09FWFBfVFJBTlNGJHdlaWdodCA8LSBhcy5udW1lcmljKEVDT0VYUF9UUkFOU0Ykd2VpZ2h0KQpgYGAKRm9yIHRoZSBtb21lbnQsIGxldCdzIGZvY3VzIG9uIHRoZSBuZXR3b3JrIHdpdGggZXhwZXJpbWVudGFsbHkgdmVyaWZpZWQgaW50ZXJhY3Rpb25zIG9ubHkuCmBgYHtyfQpsaWJyYXJ5KGlncmFwaCkKR0VYUCA8LSBncmFwaC5kYXRhLmZyYW1lKEVDT0VYUCkKYGBgCkFuZCBleHRyYWN0IGNvbm5lY3RlZCBjb21wb25lbnRzLCBhbHNvIGhhdmluZyBhIGxvb2sgYXQgdGhlIGdyYXBoIHVzaW5nIFtDeXRvc2NhcGVdKGh0dHBzOi8vY3l0b3NjYXBlLm9yZy8pLgpgYGB7cn0KQ0MgPC0gY29tcG9uZW50cyhHRVhQKQojIEhvdyBtYW55PwpsZW5ndGgodW5pcXVlKENDJG1lbWJlcnNoaXApKQp3ZSA8LSBnZXQuZWRnZS5hdHRyaWJ1dGUoR0VYUCwid2VpZ2h0IikKbGlicmFyeShSQ3kzKQpsaWJyYXJ5KHBseXIpCmN5dG9zY2FwZVBpbmcoKSAjIE5vdGUgdGhhdCBDeXRvc2NhcGUgbXVzdCBiZSBpbnN0YWxsZWQgYW5kIHJ1biB0byBwaW5nIGl0CmNyZWF0ZU5ldHdvcmtGcm9tSWdyYXBoKEdFWFAsbmV3LnRpdGxlPSdHRVhQJykKYGBgCgohW10oLi8xLnBkZil7d2lkdGg9MTAwJSBoZWlnaHQ9NDUwfQoKQWx0ZXJuYXRpdmVseSwgd2UgY2FuIGRvIHRoZSBhYm92ZSBmb3IgKkVDT0VYUF9UUkFOU0YqLCBnZXR0aW5nIGEgbXVjaCBkZW5zZXIgKG1vcmUgY29ubmVjdGVkKSBuZXR3b3JrLiBXZSdsbCB1c2UgdGhlIGxhc3QgbWVudGlvbmVkIG5ldHdvcmsgZm9yIGZ1cnRoZXIgYW5hbHlzaXMuCmBgYHtyfQpHRVhQX1RSQU5TRiA8LSBncmFwaC5kYXRhLmZyYW1lKEVDT0VYUF9UUkFOU0YpCkNDVCA8LSBjb21wb25lbnRzKEdFWFBfVFJBTlNGKQojIEhvdyBtYW55PwpsZW5ndGgodW5pcXVlKENDVCRtZW1iZXJzaGlwKSkKd2VUIDwtIGdldC5lZGdlLmF0dHJpYnV0ZShHRVhQX1RSQU5TRiwid2VpZ2h0IikKIyBUbyBmaWx0ZXIgaXQgKHdlIHdvbid0IG5lZWQgdG8gZG8gaXQgYmVjYXVzZSB3ZSBoYXZlIGFscmVhZHkgZmlsdGVyZWQgbG93IGNvbmZpZGVuY2UgdmFsdWVzKToKIyBHRVhQX1RSQU5TRiA8LSBkZWxldGVfZWRnZXMoR0VYUF9UUkFOU0YsIGVkZ2VzID0gd2hpY2god2VUIDwgbWluRXhwKSkKIyBDQ1QgPC0gY29tcG9uZW50cyhHRVhQX1RSQU5TRikgCmNyZWF0ZU5ldHdvcmtGcm9tSWdyYXBoKEdFWFBfVFJBTlNGLG5ldy50aXRsZT0nR0VYUF9UUkFOU0YnKQpgYGAKCiFbXSguLzIucGRmKXt3aWR0aD0xMDAlIGhlaWdodD00NTB9CgpUbyBpZGVudGlmeSBub24tYm90dGxlbmVjayBodWJzIGFuZCBib3R0bGVuZWNrIGh1YnMgd2UgY2FsY3VsYXRlIHRoZSBiZXR3ZWVubmVzcyBjZW50cmFsaXR5IChoaWdoIHZhbHVlID09IGJvdHRsZW5lY2spLgpgYGB7cn0KQkVUIDwtIGJldHdlZW5uZXNzKEdFWFBfVFJBTlNGLCBkaXJlY3RlZD1GQUxTRSkKaGlzdChCRVQpCmBgYApBcyB0aGV5IGRpZCBpbiBwYXBlcnMsIHdlIHNpbXBseSBkZWZpbmUgYm90dGxlbmVja3Mgb24gdGhlIGJhc2lzIG9mIHRoZSBxdWFudGlsZS4KYGBge3J9CiMgMC45IHRocmVzaG9sZCB0byBjb25zaWRlciBhIHByb3RlaW4gYSBib3R0bGVuZWNrIGluIHRoZSBQUEkKQkVUX1RBVSA8LSBxdWFudGlsZShCRVQsIDAuOSkKR0VYUF9UUkFOU0ZfREVHIDwtIGlncmFwaDo6ZGVncmVlKEdFWFBfVFJBTlNGKQpgYGAKVGhlbiB3ZSBkZWZpbmUgSFVCUy4KYGBge3J9CiMgMC45IHRocmVzaG9sZCB0byBjb25zaWRlciBhIHByb3RlaW4gYSBodWIgaW4gdGhlIFBQSQpERUdfVEFVIDwtIHF1YW50aWxlKEdFWFBfVFJBTlNGX0RFRywgMC45KQpgYGAKVG8gc2VsZWN0IGJvdHRsZW5lY2staHVicyAoQkgpIHdlIGNvbWJpbmUgdGhlIHRocmVzaG9sZHMgdG8gaWRlbnRpZnkgYSBzZXQgb2YgcHJvdGVpbnMgZnVsZmlsbGluZyBib3RoLgpgYGB7cn0KQkggPC0gVihHRVhQX1RSQU5TRikkbmFtZVtCRVQ+PUJFVF9UQVUgJiBHRVhQX1RSQU5TRl9ERUc+PURFR19UQVVdCmBgYApTZWxlY3Qgbm9uLWJvdHRsZW5lY2sgaHVicyAoTkJIKToKYGBge3J9Ck5CSCA8LSBWKEdFWFBfVFJBTlNGKSRuYW1lW0JFVDxCRVRfVEFVICYgR0VYUF9UUkFOU0ZfREVHPj1ERUdfVEFVXQpgYGAKU2VsZWN0IGJvdHRsZW5lY2sgbm9uLWh1YiAoQk5IKToKYGBge3J9CkJOSCA8LSBWKEdFWFBfVFJBTlNGKSRuYW1lW0JFVD49QkVUX1RBVSAmIEdFWFBfVFJBTlNGX0RFRzxERUdfVEFVXQpgYGAKU2VsZWN0IG5vbi1ib3R0bGVuZWNrIG5vbiBodWJzIE5CTkg6CmBgYHtyfQpOQk5IIDwtIFYoR0VYUF9UUkFOU0YpJG5hbWVbQkVUPEJFVF9UQVUgJiBHRVhQX1RSQU5TRl9ERUc8REVHX1RBVV0KYGBgCkNoZWNrIHRoZSBsZW5ndGggb2YgdGhlIHZlY3RvcnM6CmBgYHtyfQpjKAogIGxlbmd0aChCSCksIGxlbmd0aChOQkgpLCBsZW5ndGgoQk5IKSwgbGVuZ3RoKE5CTkgpCikKYGBgCk5vbi1ib3R0bGVuZWNrIG5vbi1odWJzIChOQk5IKSBhcmUgdGhlIGxhcmdlc3QgZ3JvdXAgYXMgc2FpZCBieSB0aGUgdmVyeSBiZWdpbm5pbmcuIAoKSW4gdGhpcyBwcm9qZWN0LCBpbnN0ZWFkIG9mIGhhdmluZyB0byBkbyB3aXRoIGEgbGlzdCBvZiBlc3NlbnRpYWwgZ2VuZXMgc3VjaCB0aGF0IHlvdSBjYW4gc2ltcGx5IGNhbGN1bGF0ZSB0aGUgbGVuZ3RoIG9mIHRoZSBpbnRlcnNlY3Rpb24sIHdlIG5lZWQgdG8gY2FsY3VsYXRlIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgZGlzdHJpYnV0aW9uIGZvciBhbGwgdGhlIGludGVyYWN0b3JzIG9mIHRoZSBwcm90ZWlucyB3aXRoaW4gZWFjaCBvZiB0aGUgQkggYW5kIE5CSCAoaW4gdGhpcyBwcm9qZWN0IHdlIGZvY3VzIG9uIGh1YnMpLiBUaGVyZWZvcmUsIGF0IHRoaXMgcG9pbnQgd2UgZG93bmxvYWQgZ2VuZSBleHByZXNzaW9uIGxldmVscyBmcm9tIGEgcHJvdmlkZWQgW2dlbmUgZXhwcmVzc2lvbiBjb21wZW5kaXVtIGZvciBFLiBjb2xpXShodHRwczovL2dpdGh1Yi5jb20vZW1hbnVlbGVjYXZhbGxlcmkvcGFydHlBTkRkYXRlUFBuZXR3b3Jrcy9ibG9iL21haW4vRWNvbGlfY29tcGVuZGl1bS5SRGF0YT9yYXc9dHJ1ZSksIHRoZW4gd2UnbGwgbWF0Y2ggcHJvdGVpbiBuYW1lcyBoZXJlIGluIHRoZSBncmFwaCBhbmQgaW4gdGhlIGNvbXBlbmRpdW0uCmBgYHtyfQpsb2FkKHVybCgiaHR0cHM6Ly9naXRodWIuY29tL2VtYW51ZWxlY2F2YWxsZXJpL3BhcnR5QU5EZGF0ZVBQbmV0d29ya3MvYmxvYi9tYWluL0Vjb2xpX2NvbXBlbmRpdW0uUkRhdGE/cmF3PXRydWUiKSkgIyBGcm9tIG5vdyBvbiB3ZSdsbCBmb2N1cyBvbiBaTDIgbWF0cml4LCBidXQgd2UgaGF2ZSAzIGRpZmZlcmVudCB2ZXJzaW9ucyBvZiBhIGdlbmUgZXhwcmVzc2lvbiBjb21wZW5kaXVtIGZvciBFLiBjb2xpICh3ZSBjb3VsZCd2ZSB1c2VkIEFMTF9GSU5BTF9OcmVhZHMgYW5kIEFMTF9GSU5BTF9UUE0gdG9vKS4gTW9yZW92ZXIsIHdlIGRvbuKAmXQgY2FyZSBvbiBjb25kaXRpb25zIChjb2x1bW5zIG9mIHRoZSBtYXRyaWNlcykgaW4gdGhpcyBwcm9qZWN0CmBgYApGb3IgaW5zdGFuY2UsIHRvIGhhdmUgYW4gaWRlYSBhYm91dCB0aGUgY29udGVudCBvZiB0aGUgbWF0cml4LCBoZXJlIHdlIHJlcG9ydCB0aGUgNiBmaXJzdCBjb25kaXRpb25zJyBnZW5lIGV4cHJlc3Npb24gbGV2ZWxzIGZvciB0aGUgZW50cnkgKmIzMDY1Kiwgd2hpY2ggaXMgYSBzbWFsbCBzdWJ1bml0IHJpYm9zb21hbCBwcm90ZWluIGJlbG9uZ2luZyB0byB0aGUgYmFjdGVyaWFsIHJpYm9zb21hbCBwcm90ZWluIGJTMjEgZmFtaWx5IGFsc28ga25vd24gYXMgInJwc1UiLgpgYGB7cn0KaGVhZChaTDJbImIzMDY1IixdKQpgYGAKRm9yIHRoZSBzYWtlIG9mIGNvbXBsZXRlbmVzcyBoZXJlIHdlIGFkZCBbU1RSSU5HXShodHRwczovL3N0cmluZy1kYi5vcmcvY2dpL25ldHdvcms/dGFza0lkPWJTbXNYZVVWaXZsMSZzZXNzaW9uSWQ9YjdyNW9tQVdPMFFRKSBhbmQgW0FscGhhRm9sZF0oaHR0cHM6Ly9hbHBoYWZvbGQuZWJpLmFjLnVrL2VudHJ5L0EwQTEzM04zTTcpIGVudHJpZXMgcmVsYXRpdmUgdG8gYjMwNjUvcnBzVS4KCiFbW1NUUklOR10oaHR0cHM6Ly9zdHJpbmctZGIub3JnL2NnaS9uZXR3b3JrP3Rhc2tJZD1iU21zWGVVVml2bDEmc2Vzc2lvbklkPWI3cjVvbUFXTzBRUSldKHN0cmluZ19oaXJlc19pbWFnZS5wbmcpCgohW1tBbHBoYUZvbGRdKGh0dHBzOi8vYWxwaGFmb2xkLmViaS5hYy51ay9lbnRyeS9BMEExMzNOM003KV0oYWxwaGEucG5nKQoKV2UgYXJlIGludGVyZXN0ZWQgaW4gaG93IG11Y2ggdGhlIGludGVyYWN0b3JzIGFyZSBjb3JyZWxhdGVkOyBiZWZvcmUgdGhlIGxvb3AgdG8gY2FsY3VsYXRlIHRoZSBwZWFyc29ucyBmb3IgZWFjaCBtZW1iZXIgb2YgdGhlIGJvdHRsZW5lY2sgaHViIChCSCkgZ3JvdXAsIHdlIGRlZmluZToKYGBge3J9CmZpeGVkX2ludGVydmFscyA8LSBzZXEoLTEuMDUsIDEuMDUsIC4xKQphbGxwZWFyc29uc0JIIDwtIG1hdHJpeCgwLCBuY29sPWxlbmd0aChmaXhlZF9pbnRlcnZhbHMpLTEsIG5yb3c9bGVuZ3RoKEJIKSkKYGBgCk5vdyBpdGVyYXRlIG92ZXIgdGhlIEJIOgpgYGB7cn0KZm9yKGkgaW4gMTpsZW5ndGgoQkgpKXsKICAjIE5laWdoYm9yIGdlbmVzIHN1Y2ggdGhhdCB3ZSBjYW4gZXh0cmFjdCB0aGUgY29ycmVzcG9uZGluZyByb3dzCiAgIyBmcm9tIHRoZSBjb21wZW5kaXVtIAogIGh1Yl9pbnRlcmFjdG9ycyA8LSBuZWlnaGJvcmhvb2QoR0VYUF9UUkFOU0Ysbm9kZXM9QkhbaV0pW1sxXV0KICAjIEJIW2ldIGlzIHRoZSBmaXJzdCBpbiB0aGUgaHViX2ludGVyYWN0b3JzIGxpc3Qgb2YgaW50ZXJhY3RvcnMKICAjIGV4dHJhY3RlZCB3aXRoIG5laWdoYm9yaG9vZCwgdGhlcmVmb3JlIGl0IGlzIGluIGZpcnN0IHJvdzsKICAjIHdlIGFyZSBpbnRlcmVzdGVkIGluIHRoZSBjb3JyZWxhdGlvbiBvZiBpbnRlcmFjdG9ycyBvZiBCSFtpXQogICMgd2hlbiBCSFtpXSBpcyAicHJlc2VudCIsIHRoZXJlZm9yZToKICBtYXRjaCA8LSBtYXRjaChuYW1lcyhodWJfaW50ZXJhY3RvcnMpLCByb3duYW1lcyhaTDIpKQogIGV4dHJhY3RlZHJvd3MgPC0gWkwyW21hdGNoLF0KICBiaGlfZXhwcmVzc2VkIDwtIHdoaWNoKGV4dHJhY3RlZHJvd3NbMSxdID4gbWVhbihleHRyYWN0ZWRyb3dzWzEsXSkpCiAgZXh0cmFjdGVkcm93cyA8LSBleHRyYWN0ZWRyb3dzWyxiaGlfZXhwcmVzc2VkXQogICMgUmVtb3ZlIHRoZSBodWIgdW5kZXIgYW5hbHlzaXM6CiAgZXh0cmFjdGVkcm93cyA8LSBleHRyYWN0ZWRyb3dzWy0xLF0KICAjIENhbGN1bGF0ZSBhIG1hdHJpeCBvZiBjb3JyZWxhdGlvbiBvZiBhbGwgcHJvdGVpbnMgaW50ZXJhY3RpbmcKICAjIHdpdGggQkhbaV0gdnMgdGhlbXNlbHZlcyBpbiBhbGwgY29tYmluYXRpb25zOgogIHBlYXJzb25zIDwtIGNvcih0KGV4dHJhY3RlZHJvd3MpKQogICMgQWRkaXRpb25hbGx5IHdlIHRyZWF0IGFsbCBvZiB0aGVtIGF0IG9uY2UsIHdlIHRyYW5zZm9ybSBpdCBpbnRvIGEgdmVjdG9yCiAgcGVhcnNvbnMgPC0gcGVhcnNvbnNbdXBwZXIudHJpKHBlYXJzb25zKV0KICAjIE5vdyB3ZSBzdG9yZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHBlYXJzb25zIGZvciBlYWNoIG1lbWJlciAKICAjIG9mIHRoZSBjYXRlZ29yeSAoaGVyZSBCSCkgYW5kIHRoZW4gcHV0IHRoZW0gdG9nZXRoZXI7CiAgIyB0aGlzIGNhbiBiZSBkb25lIGJ5IHB1dHRpbmcgYWxsIHBlYXJzb24gdmFsdWVzIHRvZ2V0aGVyIGZvciBhbGwgbWVtYmVycwogICMgb2YgYSBncm91cCBhbmQgdGhlbiBwbG90IGhpc3RvZ3JhbXMuCiAgIyBJbiBkb2luZyBzbyBob3dldmVyLCBodWJzIHdpdGggbGFyZ2VyIG51bWJlciBvZiBpbnRlcmFjdG9ycyB3aWxsIGdldCBtb3JlIHdlaWdodC4KICBwYXIobWZyb3c9YygxLDIpKSAjIFNldHRpbmcgdGhlIHBsb3R0aW5nIGFyZWEgaW50byBhIDEqMiBhcnJheQogIGlmKGkgPj0xICYmIGkgPD0gMyl7CiAgICAjIFdlJ2xsIHNob3cgeW91IG9ubHkgdGhlIGZpcnN0IDMgcGxvdHMgZm9yIGVhc2Ugb2YgdmlzdWFsaXphdGlvbi4KICAgICMgVG8gZ2l2ZSB0aGUgc2FtZSB3ZWlnaHQgdG8gdGhlIGRpc3RyaWJ1dGlvbiBvZiBwZWFyc29ucyB2YWx1ZSBmb3IgZGlmZmVyZW50IGh1YnM6CiAgICBoIDwtIGhpc3QocGVhcnNvbnMsIGJyZWFrcz1maXhlZF9pbnRlcnZhbHMpCiAgICAjIGgkY291bnRzL3N1bShoJGNvdW50cykgYW5kIGgkbWlkcyBpbmRpY2F0ZXMgdGhlIG1pZGRsZSBwb2ludCBvZiBlYWNoIGludGVydmFsLgogICAgIyBUaGVuLCB3aXRoaW4gdGhlIGxvb3AsIHdlIGNhbGN1bGF0ZSB0aGUgYWJvdmUgaGlzdG9ncmFtCiAgICBwbG90KGgkbWlkcywgaCRjb3VudHMvc3VtKGgkY291bnRzKSkKICB9CiAgZWxzZQogICAgaCA8LSBoaXN0KHBlYXJzb25zLCBicmVha3M9Zml4ZWRfaW50ZXJ2YWxzLCBwbG90PUZBTFNFKQogICMgYW5kIHN0b3JlIHBlYXJzb25zIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50czoKICBhbGxwZWFyc29uc0JIW2ksXSA8LSBoJGNvdW50cy9zdW0oaCRjb3VudHMpCn0KYGBgCkF0IHRoZSBlbmQgd2UgaGF2ZSAqYWxscGVhcnNvbnNCSCogcG9wdWxhdGVkIGJ5IHRoZSB2YWx1ZXMgb2YgYWxsIG1lbWJlcnMgb2YgdGhlIGdyb3VwLiBBcmUgYWxsIEJIIHNpbWlsYXIvZGlmZmVyZW50IGZvciB0aGUgd2F5IHRoZWlyIHRhcmdldHMgYXJlIGNvcnJlbGF0ZWQ/CmBgYHtyfQpsaWJyYXJ5KHBoZWF0bWFwKQpjb2xuYW1lcyhhbGxwZWFyc29uc0JIKSA8LSBoJG1pZHMKcGhlYXRtYXAoYWxscGVhcnNvbnNCSCwgY2x1c3Rlcl9jb2xzID0gRkFMU0UpCmBgYApGb3IgcGFydHkgaHVicyBtb3N0IGludGVyYWN0b3JzIHNob3VsZCBiZSBjb2V4cHJlc3NlZCBhdCB0aGUgc2FtZSB0aW1lLDogd2Ugbm90aWNlIGEgcGVhayBvbiB0aGUgcmlnaHQgKHRoZSBwcmV2aW91cyBjaG9pY2Ugb2YgYSBoaWdoIHRocmVzaG9sZCBoaWdobGlnaHRzIHRoaXMgZmFjdCkuXApDb252ZXJzZWx5LCBkYXRlIGh1YnMgaW50ZXJhY3Qgd2l0aCBkaWZmZXJlbnQgaW50ZXJhY3RvcnMgYXQgZGlmZmVyZW50IHRpbWVzLCB0aGVyZWZvcmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBjb3JyZWxhdGlvbnMgYW1vbmcgdGhlIGludGVyYWN0b3JzIHNob3VsZCBiZSBtb3JlIGZsYXQgb3Igd2l0aCBzZXZlcmFsIHBlYWtzLgpgYGB7cn0KYWxscGVhcnNvbnNOQkggPC0gbWF0cml4KDAsIG5jb2w9bGVuZ3RoKGZpeGVkX2ludGVydmFscyktMSwgbnJvdz1sZW5ndGgoTkJIKSkKZm9yKGkgaW4gMTpsZW5ndGgoTkJIKSl7CiAgaHViX2ludGVyYWN0b3JzIDwtIG5laWdoYm9yaG9vZChHRVhQX1RSQU5TRixub2Rlcz1OQkhbaV0pW1sxXV0KICBtYXRjaCA8LSBtYXRjaChuYW1lcyhodWJfaW50ZXJhY3RvcnMpLCByb3duYW1lcyhaTDIpKQogIGV4dHJhY3RlZHJvd3MgPC0gWkwyW21hdGNoLF0KICBuYmhpX2V4cHJlc3NlZCA8LSB3aGljaChleHRyYWN0ZWRyb3dzWzEsXSA+IG1lYW4oZXh0cmFjdGVkcm93c1sxLF0pKQogIGV4dHJhY3RlZHJvd3MgPC0gZXh0cmFjdGVkcm93c1ssbmJoaV9leHByZXNzZWRdCiAgZXh0cmFjdGVkcm93cyA8LSBleHRyYWN0ZWRyb3dzWy0xLF0KICBwZWFyc29ucyA8LSBjb3IodChleHRyYWN0ZWRyb3dzKSkKICBwZWFyc29ucyA8LSBwZWFyc29uc1t1cHBlci50cmkocGVhcnNvbnMpXQogIHBhcihtZnJvdz1jKDEsMikpCiAgaWYoaSA+PSAxICYmIGkgPD0gMyl7CiAgICBoIDwtIGhpc3QocGVhcnNvbnMsIGJyZWFrcz1maXhlZF9pbnRlcnZhbHMpCiAgICBwbG90KGgkbWlkcywgaCRjb3VudHMvc3VtKGgkY291bnRzKSkKICB9CiAgZWxzZQogICAgaCA8LSBoaXN0KHBlYXJzb25zLCBicmVha3M9Zml4ZWRfaW50ZXJ2YWxzLCBwbG90PUZBTFNFKQogIGFsbHBlYXJzb25zTkJIW2ksXSA8LSBoJGNvdW50cy9zdW0oaCRjb3VudHMpCn0KY29sbmFtZXMoYWxscGVhcnNvbnNOQkgpIDwtIGgkbWlkcwpwaGVhdG1hcChhbGxwZWFyc29uc05CSCwgY2x1c3Rlcl9jb2xzID0gRkFMU0UpCmBgYApXZSBjYW4gY29uZmlybSBvdXIgaHlwb3RoZXNpczogd2UgY2FuIGlkZW50aWZ5IHBlYWtzIGluIHRoZSBoZWF0bWFwIGFuZCBhIG1vcmUgInNjYXR0ZXJlZCIgcGxvdC4gVGhlIGZhY3QgdGhhdCBzZXZlcmFsIHBlYWtzIGFyZSBwcmVzZW50IG1heSBiZSBhbiBpbmRpY2F0aW9uIG9mIG11bHRpcGxlIGNvbXBsZXhlcyBmb3JtZWQgYnkgdGhlIGh1YiBhbmQgYWxzbyBvZiBtYW55IGRpZmZlcmVudCBpbnRlcmFjdGlvbnMgd2l0aCBvbmUgb3IgYSBmZXcgcGFydG5lcnMgYXQgYSB0aW1lLgoKTGV0J3Mgbm93IHNlZSBpZiB0aGVyZSBpcyBzb21lIGlubmVyIHN0cnVjdHVyZSBieSB1c2luZyBzb21lIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiB0ZWNobmlxdWUgc3VjaCBhcyBbVU1BUF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTm9ubGluZWFyX2RpbWVuc2lvbmFsaXR5X3JlZHVjdGlvbiNVbmlmb3JtX21hbmlmb2xkX2FwcHJveGltYXRpb25fYW5kX3Byb2plY3Rpb24pIGFuZCBbUENBXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QcmluY2lwYWxfY29tcG9uZW50X2FuYWx5c2lzKSBvbiBCSCBhbmQgTkJIIGdyb3Vwczogd2UnbGwgZm9jdXMgb24gVU1BUCBmaXJzdC4KYGBge3J9CmxpYnJhcnkodXdvdCkKVUJIIDwtIHVtYXAoYWxscGVhcnNvbnNCSCwgbl9jb21wb25lbnRzID0gMywgbl9uZWlnaGJvcnMgPSAyKQpsaWJyYXJ5KHJnbCkKb3B0aW9ucyhyZ2wudXNlTlVMTCA9IFRSVUUpCnBsb3QzZCh4PVVCSFssMV0sIHk9VUJIWywyXSwgej1VQkhbLDNdLCBjb2w9InJlZCIpCnJnbHdpZGdldCgpClVOQkggPC0gdW1hcChhbGxwZWFyc29uc05CSCwgbl9jb21wb25lbnRzID0gMykKcGxvdDNkKHg9VU5CSFssMV0sIHk9VU5CSFssMl0sIHo9VU5CSFssM10sIGNvbD0iZ3JlZW4iKQpyZ2x3aWRnZXQoKQpgYGAKQW5kIHdoYXQgaWYgd2Ugam9pbiB0aGUgKmFsbHBlYXJzb25zQkgqIGFuZCAqYWxscGVhcnNvbnNOQkgqIGFuZCBkbyB0aGUgc2FtZT8gV2UgY2FuIGFsc28gY29sb3IgQkggYW5kIE5CSCBpdGVtcyBkaWZmZXJlbnRseSB0byBzZWUgaWYgdGhleSBncm91cCB0b2dldGhlci4KYGBge3J9CmFsbHBlYXJzb25zIDwtIHJiaW5kKGFsbHBlYXJzb25zQkgsIGFsbHBlYXJzb25zTkJIKQpVIDwtIHVtYXAoYWxscGVhcnNvbnMsIG5fY29tcG9uZW50cyA9IDMpCnBsb3QzZCh4PVVbLDFdLCB5PVVbLDJdLCB6PVVbLDNdLCBjb2wgPSBjKHJlcCgicmVkIiwgbGVuZ3RoKEJIKSksIHJlcCgiZ3JlZW4iLCBsZW5ndGgoTkJIKSkpKQpsZWdlbmQzZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBjKCdCSCcsICdOQkgnKSwgcGNoID0gMTYsIGNvbCA9IGMoInJlZCIsICJncmVlbiIpLCBjZXg9MSwgaW5zZXQ9YygwLjAyKSkKcmdsd2lkZ2V0KCkKYGBgCldlIGNhbiByZWNvZ25pemUgdGhyZWUgZ3JvdXBzIG9mIGludGVyZXN0IGluIHRoZSBzcGFjZS4gRm9jdXNpbmcgb24gQkggcG9pbnRzIHdlIGNhbiBub3RpY2UgdGhhdCB0aGUgMTMgcG9pbnRzIGJlbG9uZ2luZyB0byB0aGF0IGNhdGVnb3J5IGFyZSBub3QgYWxsIGdyb3VwZWQgdG9nZXRoZXIsIGJ1dCB3ZSBjYW4gc2VlIHRoYXQgdGhlIG1ham9yaXR5IGFyZSB3aXRoaW4gYSBwcmVjaXNlIHJlZ2lvbiBvZiB0aGUgM0Qgc3BhY2UgYW5kIHRoYXQgdGhlIHRocmVlL2ZvdXIgb3V0c2lkZSB0aGUgImNvbmRlbnNlZCIgcmVnaW9uIHNlZW0gdG8gZm9sbG93IGEgcHJlY2lzZSB0cmFqZWN0b3J5IHRvd2FyZCB0aGUgb3RoZXIgdHdvIE5CSCBncm91cHMsIHNvIG1heWJlIGEgc2lnbiBvZiBzaW1pbGFyIGJlaGF2aW9yLiBJbiBvdGhlciB3b3JkcywgQkggcG9pbnRzIGFyZSBub3QgaXNvbGF0ZWQgaW4gdGhlIHNwYWNlLCBidXQgd2l0aGluIHJlZ2lvbnMgYWxzbyBwb3B1bGF0ZWQgYnkgTkJIIHBvaW50cyAoYXQgbGVhc3Qgb25lIEJIIHBvaW50IGluIGFueSBOQkggcmVnaW9uKS4KCk5vdyBsZXQncyBmb2N1cyBvbnRvIFBDQSB0ZWNobmlxdWUuCmBgYHtyfQpQQ0EgPC0gcHJjb21wKGFsbHBlYXJzb25zKQpzY29yZXMgPSBhcy5kYXRhLmZyYW1lKFBDQSR4KQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdChkYXRhID0gc2NvcmVzLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSByb3duYW1lcyhzY29yZXMpKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG91ciA9ICJncmF5NjUiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgY29sb3VyID0gImdyYXk2NSIpICsKICBnZW9tX3RleHQoY29sb3VyID0gYyhyZXAoInJlZCIsIGxlbmd0aChCSCkpLCByZXAoImdyZWVuIiwgbGVuZ3RoKE5CSCkpKSwgYWxwaGEgPSAwLjgsIHNpemUgPSA0KQpgYGAKUENBIG1ha2VzIGl0IGV2ZW4gY2xlYXJlciBkZWZpbml0ZWx5IGNvbmZpcm1pbmcgb3VyIHJlc3VsdHMgcHJldmlvdXNseSBvYnRhaW5lZDogcmVkIHBvaW50cyAoY29taW5nIGZyb20gdGhlIEJIIGdyb3VwKSwgZXhjZXB0IGZvciBwb2ludHMgMiBhbmQgMyBhbmQgaWYgeW91IHdhbnQgMTMgKHNpbWlsYXJseSB0byB0aGUgMy80IHBvaW50cyBkaXN0YW50IGZyb20gdGhlIG1vc3QgcG9wdWxhdGVkIGdyb3VwIGluIFVNQVAgM0QgcGxvdCksIHRlbmQgdG8gZ3JvdXAgdG9nZXRoZXIsIHdoaWxlIG90aGVyIG9uZXMgKGJlbG9uZ2luZyB0byB0aGUgTkJIIGdyb3VwKSB0ZW5kIHRvIGJlIHNwYXJzZXIgKGN1cmlvdXNseSBzaW1pbGFyIHRvIHRoZSBmYWN0IHRoYXQgcHJldmlvdXNseSB3ZSBvYnRhaW5lZCBhIG1vcmUgInNjYXR0ZXJlZCIgaGVhdG1hcCkuCgojIFNlc3Npb24gaW5mb3M6CmBgYHtyfQpjeXRvc2NhcGVWZXJzaW9uSW5mbygpCnNlc3Npb25JbmZvKCkKYGBg